package com.itfsw.jenkins.plugins;

import com.google.gson.Gson;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.qiniu.util.StringUtils;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


public class QiniuPublisher extends Recorder {

    private final List<QiniuPublisherEntry> entries = new ArrayList<QiniuPublisherEntry>();

    public QiniuPublisher() {
        super();
    }

    @Override
    public boolean perform(AbstractBuild build, Launcher launcher,
                           BuildListener listener) throws IOException, InterruptedException {
        // This is where you 'build' the project.
        // Since this is a dummy, we just say 'hello world' and call that a
        // build.

        // This also shows how you can consult the global configuration of the
        // builder
        FilePath ws = build.getWorkspace();
//        String wsPath = ws.getRemote() + File.separator;
        PrintStream logger = listener.getLogger();
        Map<String, String> envVars = build.getEnvironment(listener);
        final boolean buildFailed = build.getResult() != Result.SUCCESS;
        if (buildFailed) logger.println("---任务构建失败---");

        logger.println("开始读取七牛配置:");
        for (QiniuPublisherEntry entry : this.entries) {

            //对可输入内容字段进行变量替换
            String source = Util.replaceMacro(entry.source, envVars);
            String relative = Util.replaceMacro(entry.relative, envVars);
            String bucket = Util.replaceMacro(entry.bucket, envVars);
            String prefix = Util.replaceMacro(entry.prefix, envVars);

            logger.println("七牛参数生成：");
            logger.println("文件夹路径：" + source);
            logger.println("文件相对路径：" + relative);
            logger.println("要上传到的 bucket：" + bucket);
            logger.println("上传文件路径前缀：" + prefix);

            if (entry.noUploadOnFailure && buildFailed) {
                logger.println("构建失败,跳过上传");
                continue;
            }

            QiniuConfiguration configuration = QiniuConfiguration.get();

            //密钥配置
            Auth auth = Auth.create(configuration.getAccessKey(), configuration.getSecretKeyPlainText());

            //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。
            Configuration c = new Configuration(Region.autoRegion());

            logger.println("---七牛任务开始上传---");

            // 相对路径
            String relativePath = relative != null ? ws.child(relative).getRemote() : null;

            //创建上传对象
            UploadManager uploadManager = new UploadManager(c);

            FilePath[] paths = ws.list(source);
            for (FilePath path : paths) {


                String fullPath = path.getRemote();
                logger.println("上传文件 " + fullPath + " 到 " + bucket + " 开始.");

                String key;
                if (relativePath == null) {
                    key = path.getName();
                } else {
                    // 相对路径
                    key = fullPath.replace(relativePath, "");
                    // 路径格式化
                    if (relative.endsWith("/") || relative.endsWith("\\")){
                        key = key.substring(1);
                    }
                    key = key.replace(File.separator, "/");
                }

                // 前缀
                if (!StringUtils.isNullOrEmpty(prefix)) {
                    key = prefix + key;
                }

                int insertOnley = entry.noUploadOnExists ? 1 : 0;
                //上传策略。同名文件不允许再次上传。 文件相同，名字相同，返回上传成功。文件不同，名字相同，返回上传失败提示文件已存在。
                StringMap putPolicy = new StringMap();
                putPolicy.put("insertOnly", insertOnley);

                //简单上传，使用默认策略，只需要设置上传的空间名就可以了
                String uploadToken = auth.uploadToken(bucket, key, 3600, putPolicy);

                //调用put方法上传 文件路径，上传后保存文件名，token
                Response res = uploadManager.put(fullPath, key, uploadToken);

                //打印返回的信息
                String bodyString = res.bodyString();

                //默认body返回hash和key值
                DefaultPutRet defaultPutRet = new Gson().fromJson(bodyString, DefaultPutRet.class);
//                    String hashString = defaultPutRet.hash;
                //获得文件保存在空间中的资源名。
                String keyString = defaultPutRet.key;

                logger.println("上传 " + keyString + " 到 " + bucket + " 成功." + bodyString);
            }
            logger.println("---七牛任务上传完成---");
        }
        logger.println("七牛云任务执行完成...");
        return true;
    }

    // Overridden for better type safety.
    // If your plugin doesn't really define any property on Descriptor,
    // you don't have to do this.
    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    /**
     * Descriptor for {@link QiniuPublisher}. Used as a singleton. The class is
     * marked as public so that it can be accessed from views.
     * <p>
     * <p>
     * See
     * <tt>src/main/resources/hudson/plugins/hello_world/HelloWorldBuilder/*.jelly</tt>
     * for the actual HTML fragment for the configuration screen.
     */
    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            // Indicates that this builder can be used with all kinds of project
            // types
            return true;
        }

        /**
         * This human readable name is used in the configuration screen.
         */
        public String getDisplayName() {
            return "上传到七牛";
        }

        @Override
        public QiniuPublisher newInstance(StaplerRequest req, JSONObject formData) throws FormException {
            List<QiniuPublisherEntry> entries = req.bindJSONToList(QiniuPublisherEntry.class,
                    formData.get("e"));
            QiniuPublisher pub = new QiniuPublisher();
            pub.getEntries().addAll(entries);
            return pub;
        }
    }

    public BuildStepMonitor getRequiredMonitorService() {
        return BuildStepMonitor.STEP;
    }

    public List<QiniuPublisherEntry> getEntries() {
        return entries;
    }

}
